# -*- mode: python -*-
#
#

# system imports
import time

# DDB imports
from ddb.log import log
from ddb.tools import localImport
from ddb.config import configFile
from ddb.user import userManager
from ddb.conference import conferenceManager
from ddb.module import moduleManager
from ddb.event import event

# Twisted imports
from twisted.internet import protocol, reactor

class ITransport:
    capabilities = {
        'conference': False
    }

    def __init__(self, manager, name, config):
        self.manager = manager
        self.config  = config
        self.run     = False
        self.name    = name

    def start(self):
        self.run = True
        log.msg('%s has no start method defined' % str(self.__class__))
        return False

    def stop(self):
        self.run = False
        log.msg('%s has no stop method defined' % str(self.__class__))
        return False

class ITransportProtocol:
    """Basic protocol skell."""

    type = None
    lag  = 0.0

    def __init__(self):
        self.identity    = ['<SELF>', '']
        self.name        = '%x' % abs(id(self))
        self.online      = False
        self.conferences = conferenceManager()
        self.modules     = moduleManager
        self.users       = userManager(*self.identity)

    #
    # Generic connection-related
    #

    def connectionMade(self):
        self.name   = self.factory.name
        self.online = True
        log.msg('Transport %s is now online' % str(self.__class__))

    def connectionLost(self, reason = ''):
        self.online = False
        log.msg('Transport %s is now offline' % str(self.__class__))
        self.users.flush()
        self.conferences.flush()

    def reply(self, message, e=None):
        pass

    def say(self, target, message):
        pass

    #
    # Status updates about myself
    #

    def signedOn(self):
        log.msg('I signed on to the server as %s' % self.identity[0])
        event(self, 'signedOn') 

    def openedConference(self, target):
        log.msg('I joined conference at %s' % (str(target)), debug=True)
        self.conferences.add(target)
        self.conferences.userAdd(target, self.users.users['<SELF>'])

    def closedConference(self, target):
        log.msg('I parted conference at %s' % (str(target)), debug=True)
        self.conferences.userRemove(target, self.users.users['<SELF>'])
        self.conferences.remove(target)

    def message(self, senderIdentity, senderMask, target, message):
        log.msg('message from %s on %s: %s' % (senderIdentity, target, message), debug=True)
        user = self.users.update(senderIdentity, target)
        event(self, 'message', user=user, target=target, message=message)

    #
    # Status updates about others
    #

    def joinedConference(self, senderIdentity, senderMask, target):
        log.msg('user %s joined conference at %s' % (str(senderIdentity), str(target)), debug=True)
        user = self.users.add(senderIdentity, senderMask)
        self.conferences.userAdd(target, user)
        event(self, 'joinedConference', user=user, target=target)
        del user

    def partedConference(self, senderIdentity, senderMask, target, reason=''):
        log.msg('user %s parted conference at %s' % (str(senderIdentity), str(target)), debug=True)
        self.conferences.userRemove(target, user)
        # check if this user still shares any conference with me, if not, remove entry
        # on transports like IRC we don't get online/offline notifications if the
        # user does not share a conference with us
        user = self.users.findByIdentity(senderIdentity)
        if not user:
            return # hmm we did get a notification, but we didn't see the user before
        if self.conferences.userLocate(user):
            self.users.remove(senderIdentity)
        event(self, 'partedConference', user=user, target=target, reason=reason)
        del user

class ITransportManager:
    """Keeps track of all transports."""

    def __init__(self):
        self.config     = None
        self.started    = time.time()
        self.transports = []
        self.loadedMods = False

    def loadModules(self):
        if self.config and not self.loadedMods:
            if not self.config.sectionExists('general'):
                return
            moduleDirs = self.config.get('general', 'modules')
            if not moduleDirs:
                log.msg('Could not find config option "module" in "general", starting without modules')
                return
            for moduleDir in moduleDirs:
                moduleManager.loadDir(moduleDir)
            self.loadedMods = True

    def addTransport(self, protocol, name, config):
        """Add a new transport instance to the pool of transports."""
        transportModule = 'ddb.transport.%s' % protocol
        try:
            module = localImport(transportModule)
        except ImportError, e:
            log.err('Could not load transport %s: %s' % (protocol, str(e)))
            return
        log.msg('Loaded transport %s' % protocol)
        try:
            transport = getattr(module, 'transport')
        except AttributeError, e:
            log.err('Module %s has no class "transport", fix it' % transportModule)
            return
        newTransport = transport(self, name, config)
        self.transports.append(newTransport)

    def loadConfig(self, config):
        self.config = configFile(config)
        self.config.load(False)
        if not self.config.sectionExists('general'):
            log.msg('Could not find config section "general" in %s' % config)
            return
        log.msg('Finding servers to connect to in %s' % config, debug=True)
        if not self.config.get('general', 'connect'):
            log.msg('Could not find option "connect" in "general" in %s, doing nothing' % config)
            return
        print self.config.get('general', 'connect')
        for server in self.config.get('general', 'connect'):
            self.loadTransportFromConfig(server)

    def loadTransportFromConfig(self, name):
        section = 'server:%s' % name
        if not self.config.sectionExists(section):
            log.msg('Could not find section "%s"' % section)
            return
        # find transport type
        transportName = self.config.get(section, 'transport')
        if not transportName:
            log.msg('Could not find transport in section "%s"' % section)
            return
        self.addTransport(transportName[0], name, self.config.sectionGet(section))

    def startTransports(self):
        """Give all transports the start signal."""
        for transport in self.transports:
            transport.start()

    def run(self):
        """Run all reactors."""
        self.loadModules()
        reactor.run()

transportManager = ITransportManager()

# vim:ts=4:sw=4:et:
